<template>
    <div id="dom1">
    </div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 导入 GUI
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js"
// 导入 hdr 加载器
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
// 导入 gltf 加载器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 压缩过的 gltf 用 DRACOLoader 解析器
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
// 导入 tween 补间动画
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js';

export default {
    data() {
        return {
            screenWidth: document.innerWidth,
            guis: null,
        }
    },
    computed: {

    },
    beforeDestroy() {
        // 销毁 GUI 实例
        if (this.guis) {
            this.guis.destroy();
        }
    },

    methods: {
        // 创建三角形平面 最原生的
        fnNewGeometry() {
            const geometry = new THREE.BufferGeometry();
            // 创建顶点数据，顶点是有顺序的，逆时针为正面
            const vertices = new Float32Array([
                0.0, 0.0, -100.0, //顶点1
                50.0, 0.0, -100.0,//顶点2
                50.0, 50.0, -100.0,//顶点3
                0.0, 50.0, -100.0,//顶点4
            ])
            geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
            // 创建顶点属性
            const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
            // 创建索引 此时就会成正方形
            geometry.setIndex(new THREE.BufferAttribute(indices, 1))
            // 设置两个顶点组，形成2个材质
            geometry.addGroup(0, 3, 0); //参数 从0顶点开始添加3个顶点，用第一个材质
            geometry.addGroup(3, 3, 1);

            // 创建材质
            const material = new THREE.MeshBasicMaterial({
                color: 0x00ff00,
                side: THREE.DoubleSide,//双面都能看到
            })
            const material1 = new THREE.MeshBasicMaterial({
                color: 0xff0000,
                side: THREE.DoubleSide,//双面都能看到
            })

            return new THREE.Mesh(geometry, [material, material1]);
        },
        // 创建有材质的平面图形
        fnNewGeometryHaveImg() {
            // 创建纹理加载器
            let textureLoader = new THREE.TextureLoader();
            // 加载纹理
            let texture = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png");
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            // 加载AO贴图（环境遮挡贴图）
            let aoMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png");
            // alpha贴图(透明度贴图) 黑色完全透明，白色完全不透明
            let alphaMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png")
            // 光照贴图
            let lightMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-31fd3feb-4c47-429c-8b90-c06607192ec4.jpeg")
            // 高光贴图 白色反射 黑色不反射
            let specularMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-31fd3feb-4c47-429c-8b90-c06607192ec4.jpeg")

            let planeGeometry = new THREE.PlaneGeometry(100, 100)
            let planeMaterial = new THREE.MeshBasicMaterial({
                map: texture,
                aoMap: aoMap,
                // alphaMap: alphaMap,
                // lightMap: lightMap,
                // specularMap:specularMap,
                color: 0xffffff,
                side: THREE.DoubleSide,//双面都能看到
                transparent: true, //允许透明
                reflectivity: 0.8,//反射强度
            })
            //为改图片设置环境贴图反射 
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/001.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                planeMaterial.envMap = texture;
                //环境贴图
            });
            return new THREE.Mesh(planeGeometry, planeMaterial);
        },
        // 创建有材质的正方体
        fnNewMaterialCube() {
            let geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个几何对象
            // 创建纹理加载器
            let textureLoader = new THREE.TextureLoader();
            // 加载纹理
            let texture = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-9cc5dc5f-5f1a-41fd-917d-6d6045f58f0f.jpeg");
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            let meterial = new THREE.MeshBasicMaterial({
                map: texture,
                color: 0xffffff,
                side: THREE.DoubleSide,//双面都能看到
                transparent: true, //允许透明
                reflectivity: 0.8,//反射强度
            })
            //为改图片设置环境贴图反射 
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/001.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                meterial.envMap = texture;
                //环境贴图
            });
            return new THREE.Mesh(geometry, meterial);

        },
        // 有材质的球体
        fnNewRedios(textureImg, radius) {
            const geometry = new THREE.SphereGeometry(radius, 32, 16);
            let textureLoader = new THREE.TextureLoader();
            let texture = textureLoader.load(textureImg);
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            const material = new THREE.MeshBasicMaterial({ map: texture, });
            return new THREE.Mesh(geometry, material);

        },
        // hdr加载器
        fnRGBLoader(scene) {
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/001.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                scene.background = texture;
                //环境贴图
                scene.environment = texture;
            });
        },
        // 雾
        fnFog(scene) {
            // 线性雾
            // scene.fog = new THREE.Fog(0x999999,0.01,1000)
            //指数雾
            scene.fog = new THREE.FogExp2(0x999999, 0.1);
        },
        fnAddGui(cube, name) {
            this.guis = new GUI();
            // let guiParent = document.getElementById('dom1');
            this.guis.domElement.style.position = 'absolute';
            this.guis.domElement.style.zIndex = '5';
            this.guis.domElement.style.top = '145px';
            this.guis.domElement.style.right = '30px';
            // 添加按钮
            this.guis.add(this, "Fullscreen").name("全屏")
            this.guis.add(this, "ExitFullScreen").name("退出全屏");

        },
        fnCube1Gui(cube, name) {
            // 控制立方体 step 每次移动增加的数值
            let folder = this.guis.addFolder(`${name}参数`)
            folder.closed = true; // 设置文件夹的默认状态为折叠
            folder.add(cube.position, "x", -100, 500).step(10).name("立方体x轴位置")
            folder.add(cube.position, "y", -100, 500).step(10).name("立方体y轴位置").onFinishChange((val) => {
                console.log("拖动结束触发事件")
            })
            folder.add(cube.position, "z", -100, 500).step(10).name("立方体z轴位置").onChange(() => {
                console.log("拖动触发事件")
            })
            // guiParent.appendChild(this.guis.domElement);
        },
        fnCube3Gui(cube3, meterial2, name) {
            let folder = this.guis.addFolder(`${name}参数`)

            folder.add(meterial2, "wireframe").name("材质2线框")
            folder.addColor({
                cubeColor: "#0xaaff11"
            }, "cubeColor").name("立方体颜色").onChange((val) => {
                cube3.material.color.set(val)
            })
        },
        Fullscreen() {
            console.log("__123_")
            document.body.requestFullscreen()
        },
        ExitFullScreen() {
            document.exitFullscreen();
        },
        // 主函数
        fnTreeUse() {
            let width = window.innerWidth; //窗口宽度
            let height = window.innerHeight; //窗口高度RGBELoader
            let k = width / height; //窗口宽高比
            let s = 400; //三维场景显示范围控制系数，系数越大，显示的范围越大
            let DOM = document.getElementById("dom1");

            // 创建画布
            const scene = new THREE.Scene();
            const renderer = new THREE.WebGLRenderer();
            renderer.setSize(width, height);
            // 画布全景背景加载
            this.fnRGBLoader(scene)

            // 创造几何体
            let geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个几何对象
            // 创造材质
            let meterial = new THREE.MeshLambertMaterial({ color: 0x00ff11 });
            let meterial2 = new THREE.MeshLambertMaterial({ color: 0xaaff11 });
            //  设置材质为线框模式
            meterial2.wireframe = true
            //创建元素物体（网格）
            let cube = new THREE.Mesh(geometry, meterial);
            cube.position.set(-200, 50, 200);//x y z 几何体位置 同上拆分模式写法
            // cube.position.x = 100;
            // cube.position.y = 50;
            // cube.position.z = 100;
            let cube2 = new THREE.Mesh(geometry, meterial); //创建第二个几何体 可以复用形状和材质
            cube2.position.set(-100, 100, 0);
            let cube3 = new THREE.Mesh(geometry, [meterial, meterial2, meterial2, meterial2, meterial2, meterial2]); //创建第3个几何体 6个面6个材质
            cube3.position.set(-100, 50, 100);

            let cube4 = this.fnNewGeometry();
            let cube5 = this.fnNewGeometryHaveImg()
            cube5.position.set(-100, 200, 100);
            let cube6 = this.fnNewMaterialCube()
            cube6.position.set(-100, 200, 100);
            let sun = this.fnNewRedios("./img/sun.jpeg", 32);
            sun.position.set(100, 0, 100);
            let earth = this.fnNewRedios("./img/earth.png", 16)
            earth.position.set(100, 0, 0);
            let moon = this.fnNewRedios("./img/yueliang.jpg", 4)
            moon.position.set(30, 0, 0);
            // 添加几何体
            cube.add(cube2); //添加到cube上，postion相对cube
            scene.add(cube);
            scene.add(cube3);
            scene.add(cube4);
            scene.add(cube5);
            scene.add(cube6);
            earth.add(moon);
            sun.add(earth);
            scene.add(sun);
            // 局部缩放立方体cube
            cube.scale.set(0.5, 0.5, 0.5);
            // 雾气加载
            // this.fnFog(scene)

            // 建模加载器实例化
            const gltfLoad = new GLTFLoader();
            gltfLoad.load(
                "./model/001.glb",
                // j加载建模完的回调函数
                (gltf) => {
                    console.log("____gltf,", gltf)
                    let cubeGlb = gltf.scene;
                    cubeGlb.position.set(80, 50, -40);
                    gltf.scene.traverse((child) => {
                        if (child.isMesh) {
                            // 修改材质属性
                            child.material.color.setHex(0xff0000); // 设置颜色为红色
                            // 其他修改材质的操作...
                        }
                    });
                    scene.add(cubeGlb)
                }
            )

            //点光源
            // let point = new THREE.PointLight(0x00ff00);
            // point.position.set(100, 100, 100); //点光源位置
            // scene.add(point); //点光源添加到场景中

            //环境光
            let ambient = new THREE.AmbientLight(0xffffff);
            scene.add(ambient);

            // 相机位置
            const camera = new THREE.PerspectiveCamera(45, k, 0.1, 10000);
            camera.position.set(1000, 0, 1000); //设置相机位置
            camera.lookAt(scene.position); //设置相机方向(指向的场景对象)

            // // 创建射线
            const raycaster = new THREE.Raycaster();
            // // 创建鼠标向量
            const mouse = new THREE.Vector2();
            DOM.addEventListener("click", (event) => {
                mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
                mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
                console.log("mouse.x:", mouse.x, "___mouse.y:", mouse.y)
                // 通过摄像机和鼠标位置更新射线
                raycaster.setFromCamera(mouse, camera);
                // 计算物体和射线的焦点
                const intersects = raycaster.intersectObjects(scene.children);
                console.log("__intersects__", intersects);

                if (intersects.length > 0) {
                    intersects[0].object.material.color.set(0xff0000)
                }
            })

            // Dom添加
            DOM.appendChild(renderer.domElement);
            // 添加坐标系
            const axesHelper = new THREE.AxesHelper(500);
            scene.add(axesHelper);
            // 添加局部坐标系
            // const axesHelperCube = new THREE.AxesHelper(150);

            // 添加控制器
            const controls = new OrbitControls(camera, DOM);
            controls.enableDamping = true; //带阻尼
            controls.dampingFactor = 0.08;//阻尼系数，越小越滑
            // controls.autoRotate = true;//相机自动旋转（坐标系也转动）

            // 补间动画
            const sunTween = new TWEEN.Tween(sun.position);
            sunTween.to({ x: 200 }, 10000);
            sunTween.repeat(Infinity);//循环无数次
            sunTween.yoyo(true);//循环往复
            sunTween.delay(3000);//每次运行等待3s 延迟操作   
            sunTween.start();
            // 渲染场景
            function fnAnimate() {
                controls.update();
                // cube几何体旋转
                // cube.rotation.x += 0.01;
                cube.rotation.y += 0.01;
                // cube.rotation.z += 0.01;
                //cube几何体移动
                // if(cube.position.x < 300){
                //      cube.position.x += 1;
                // }
                // 宇宙旋转
                sun.rotation.y += 0.005;
                earth.rotation.y += 0.01;
                moon.rotation.y += 0.015;

                // 更新补间动画
                sunTween.update();
                renderer.render(scene, camera)
                requestAnimationFrame(fnAnimate);
            }
            fnAnimate()

            // renderer.render(scene, camera)

            // 监听事件，监听页面变化并更新视图
            window.addEventListener("resize", () => {
                renderer.setSize(window.innerWidth, window.innerHeight);//重置渲染器宽高比
                camera.aspect = window.innerWidth / window.innerHeight; //重置相机位置
                camera.updateProjectionMatrix();//更新
            })
            // GUI函数
            this.fnAddGui(cube, "cube");
            this.fnCube1Gui(cube, "cube");
            this.fnCube3Gui(cube3, meterial2, "cube3");
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.fnTreeUse()
        })
        // 声明GUI操作面板



        // const that = this;
        // window.onresize = () => (() => {
        //     that.screenWidth = window.innerWidth;
        // })();

    },
    watch: {
        // screenWidth(newVal, oldVal) {
        //     if(newVal){

        //     }
        // }
    }
}
</script>
<style scoped lang="less">
* {
    margin: 0;
    padding: 0;
}

.dom1 {
    width: 100%;
    height: 100%;
}

canvas {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}
</style>